home *** CD-ROM | disk | FTP | other *** search
-
- Chapter 5 - Functions, variables, and prototypes
-
-
- OUR FIRST USER DEFINED FUNCTION
-
- Load and examine the file SUMSQRES.C for an example of
- a C program with functions. Actually this is not the first
- function we have encountered because the "main" program we
- have been using all along is technically a function, as is
- the "printf" function. The "printf" function is a library
- function that was supplied with your compiler.
-
- Notice the executable part of this program which begins
- in line 8. It begins with a line that simply says
- "header()", which is the way to call any function. The
- parentheses are required because the C compiler uses them to
- determine that it is a function call and not simply a
- misplaced variable. When the program comes to this line of
- code, the function named "header" is called, its statements
- are executed, and control returns to the statement following
- this call. Continuing on we come to a "for" loop which will
- be executed 7 times and which calls another function named
- "square" each time through the loop, and finally a function
- named "ending" will be called and executed. For the moment
- ignore the "index" in the parentheses of the call to
- "square". We have seen that this program therefore calls a
- header, 7 square calls, and an ending. Now we need to define
- the functions.
-
- DEFINING THE FUNCTIONS
-
- Following the main program you will see another program
- that follows all of the rules set forth so far for a "main"
- program except that it is named "header()". This is the
- function which is called from within the main program. Each
- of these statements are executed, and when they are all
- complete, control returns to the main program.
-
- The first statement sets the variable "sum" equal to
- zero because we will use it to accumulate a sum of squares.
- Since the variable "sum" is defined as an integer type
- variable prior to the main program, it is available to be
- used in any of the following functions. It is called a
- "global" variable, and it's scope is the entire program and
- all functions. More will be said about the scope of
- variables near the end of this chapter. The next statement
- outputs a header message to the monitor. Program control
- then returns to the main program since there are no
- additional statements to execute in this function.
-
- It should be clear to you that the two executable lines
- from this function could be moved to the main program,
- replacing the header call, and the program would do exactly
- the same thing that it does as it is now written. This does
-
-
- Page 31
-
-
-
-
-
-
-
-
-
- Chapter 5 - Functions, variables, and prototypes
-
-
- not minimize the value of functions, it merely illustrates
- the operation of this simple function in a simple way. You
- will find functions to be very valuable in C programming.
-
- PASSING A VALUE TO A FUNCTION
-
- Going back to the main program, and the "for" loop
- specifically, we find the new construct from the end of the
- last lesson used in the last part of the "for" loop, namely
- the "index++". You should get used to seeing this, as you
- will see it a lot in C programs.
-
- In the call to the function "square", we have an added
- feature, namely the variable "index" within the parentheses.
- This is an indication to the compiler that when you go to
- the function, you wish to take along the value of index to
- use in the execution of that function. Looking ahead at the
- function "square", we find that another variable name is
- enclosed in its parentheses, namely the variable "number".
- This is the name we prefer to call the variable passed to
- the function when we are in the function. We can call it
- anything we wish as long as it follows the rules of naming
- an identifier. Since the function must know what type the
- variable is, it is defined following the function name but
- before the opening brace of the function itself. Thus, the
- line containing "int number;" tells the function that the
- value passed to it will be an integer type variable. With
- all of that out of the way, we now have the value of index
- from the main program passed to the function "square", but
- renamed "number", and available for use within the function.
- This is the "classic" style of defining function variables
- and has been in use since C was originally defined. A newer
- method is gaining in popularity due to its many benefits and
- will be discussed later in this chapter.
-
- Following the opening brace of the function, we define
- another variable "numsq" for use only within the function
- itself, (more about that later) and proceed with the
- required calculations. We set "numsq" equal to the square
- of number, then add numsq to the current total stored in
- "sum". Remember that "sum += numsq" is the same as "sum =
- sum + numsq" from the last lesson. We print the number and
- its square, and return to the main program.
-
- MORE ABOUT PASSING A VALUE TO A FUNCTION
-
- When we passed the value of "index" to the function, a
- little more happened than meets the eye. We did not
- actually pass the value of index to the function, we
- actually passed a copy of the value. In this way the
- original value is protected from accidental corruption by a
-
-
- Page 32
-
-
-
-
-
-
-
-
-
- Chapter 5 - Functions, variables, and prototypes
-
-
- called function. We could have modified the variable
- "number" in any way we wished in the function "square", and
- when we returned to the main program, "index" would not have
- been modified. We thus protect the value of a variable in
- the main program from being accidentally corrupted, but we
- cannot return a value to the main program from a function
- using this technique. We will find a well defined method of
- returning values to the main program or to any calling
- function when we get to arrays and another method when we
- get to pointers. Until then the only way you will be able
- to communicate back to the calling function will be with
- global variables. We have already hinted at global
- variables above, and will discuss them in detail later in
- this chapter.
-
- Continuing in the main program, we come to the last
- function call, the call to "ending". This call simply calls
- the last function which has no local variables defined. It
- prints out a message with the value of "sum" contained in it
- to end the program. The program ends by returning to the
- main program and finding nothing else to do. Compile and
- run this program and observe the output.
-
- NOW TO CONFESS A LITTLE LIE
-
- I told you a short time ago that the only way to get a
- value back to the main program was through use of a global
- variable, but there is another way which we will discuss
- after you load and display the file named SQUARES.C. In
- this file we will see that it is simple to return a single
- value from a called function to the calling function. But
- once again, it is true that to return more than one value,
- we will need to study either arrays or pointers.
-
- In the main program, we define two integers and begin a
- "for" loop which will be executed 8 times. The first
- statement of the "for" loop is "y = squ(x);", which is a new
- and rather strange looking construct. From past experience,
- we should have no trouble understanding that the "squ(x)"
- portion of the statement is a call to the "squ" function
- taking along the value of "x" as a variable. Looking ahead
- to the function itself we find that the function prefers to
- call the variable "in" and it proceeds to square the value
- of "in" and call the result "square". Finally, a new kind
- of a statement appears, the "return" statement. The value
- within the parentheses is assigned to the function itself
- and is returned as a usable value in the main program.
- Thus, the function call "squ(x)" is assigned the value of
- the square and returned to the main program such that "y" is
- then set equal to that value. If "x" were therefore
-
-
-
- Page 33
-
-
-
-
-
-
-
-
-
- Chapter 5 - Functions, variables, and prototypes
-
-
- assigned the value 4 prior to this call, "y" would then be
- set to 16 as a result of this line of code.
-
- Another way to think of this is to consider the
- grouping of characters "squ(x)" as another variable with a
- value that is the square of "x", and this new variable can
- be used any place it is legal to use a variable of its type.
- The values of "x" and "y" are then printed out.
-
- To illustrate that the grouping of "squ(x)" can be
- thought of as just another variable, another "for" loop is
- introduced in which the function call is placed in the print
- statement rather than assigning it to a new variable.
-
- One last point must be made, the type of variable
- returned must be defined in order to make sense of the data,
- but the compiler will default the type to integer if none is
- specified. If any other type is desired, it must be
- explicitly defined. How to do this will be demonstrated in
- the next example program.
-
- Compile and run this program which also uses the
- "classic" method of defining function variables.
-
- FLOATING POINT FUNCTIONS
-
- Load the program FLOATSQ.C for an example of a function
- with a floating point type of return. It begins by defining
- a global floating point variable we will use later. Then in
- the "main" part of the program, an integer is defined,
- followed by two floating point variables, and then by two
- strange looking definitions. The expressions "sqr()" and
- "glsqr()" look like function calls and they are. This is
- the proper way in C to define that a function will return a
- value that is not of the type "int", but of some other type,
- in this case "float". This tells the compiler that when a
- value is returned from either of these two functions, it
- will be of type "float". This is, once again, the "classic"
- method of defining functions.
-
- Now refer to the function "sqr" near the center of the
- listing and you will see that the function name is preceded
- by the name "float". This is an indication to the compiler
- that this function will return a value of type "float" to
- any program that calls it. The function is now compatible
- with the call to it. The line following the function name
- contains "float inval;", which indicates to the compiler
- that the variable passed to this function from the calling
- program will be of type "float".
-
-
-
-
- Page 34
-
-
-
-
-
-
-
-
-
- Chapter 5 - Functions, variables, and prototypes
-
-
- The next function, namely "glsqr", will also return a
- "float" type variable, but it uses a global variable for
- input. It also does the squaring right within the return
- statement and therefore has no need to define a separate
- variable to store the product.
-
- The overall structure of this program should pose no
- problem and will not be discussed in any further detail. As
- is customary with all example programs, compile and run this
- program.
-
- THERE IS A BUG IN THE FIRST VERSION OF TURBO C
-
- When you run this program, using version 1.0 of Turbo
- C, you will find that the function named "sqr()" will return
- a value of zero. This is because it receives a zero from
- the calling program. The program is written correctly but
- the compiler has a bug in it. A call to Borland resulted in
- a fix by simply using the "modern" method of function
- definition rather than the "classic" which has been used to
- this point. As you read articles on C, you will see
- programs written in the "classic" style, so you need to be
- capable of reading them. It would be highly recommended,
- however, that you learn and use the "modern" method which
- will be covered shortly in this tutorial. We will return to
- this program and show how to fix it so that it will work in
- spite of the bug.
-
- Note that this bug is fixed in TURBO C version 1.5.
-
- SCOPE OF VARIABLES
-
- Load the next program, SCOPE.C, and display it for a
- discussion of the scope of variables in a program. Ignore
- the 4 statements in lines 2 through 5 of this program for a
- few moments, and we will discuss them later.
-
- The first variable defined is a global variable "count"
- which is available to any function in the program since it
- is defined before any of the functions. In addition, it is
- always available because it does not come and go as the
- program is executed. (That will make sense shortly.)
- Farther down in the program, another global variable named
- "counter" is defined which is also global but is not
- available to the main program since it is defined following
- the main program. A global variable is any variable that is
- defined outside of any function. Note that both of these
- variables are sometimes referred to as external variables
- because they are external to any functions.
-
-
-
-
- Page 35
-
-
-
-
-
-
-
-
-
- Chapter 5 - Functions, variables, and prototypes
-
-
- Return to the main program and you will see the
- variable "index" defined as an integer. Ignore the word
- "register" for the moment. This variable is only available
- within the main program because that is where it is defined.
- In addition, it is an "automatic" variable, which means that
- it only comes into existence when the function in which it
- is contained is invoked, and ceases to exist when the
- function is finished. This really means nothing here
- because the main program is always in operation, even when
- it gives control to another function. Another integer is
- defined within the "for" braces, namely "stuff". Any
- pairing of braces can contain a variable definition which
- will be valid and available only while the program is
- executing statements within those braces. The variable will
- be an "automatic" variable and will cease to exist when
- execution leaves the braces. This is convenient to use for
- a loop counter or some other very localized variable.
-
- MORE ON "AUTOMATIC" VARIABLES
-
- Observe the function named "head1" in line 26 which
- looks a little funny because of "void" being used twice.
- The purpose of the uses of the word "void" will be explained
- shortly. The function contains a variable named "index",
- which has nothing to do with the "index" of the main
- program, except that both are automatic variables. When the
- program is not actually executing statements in this
- function, this variable named "index" does not even exist.
- When "head1" is called, the variable is generated, and when
- "head1" completes its task, the variable in "head1" named
- "index" is eliminated completely from existence. Keep in
- mind however that this does not affect the variable of the
- same name in the main program, since it is a completely
- separate entity.
-
- Automatic variables therefore, are automatically
- generated and disposed of when needed. The important thing
- to remember is that from one call to a function to the next
- call, the value of an automatic variable is not preserved
- and must therefore be reinitialized.
-
- WHAT ARE STATIC VARIABLES?
-
- An additional variable type must be mentioned at this
- point, the "static" variable. By putting the reserved word
- "static" in front of a variable declaration within a
- function, the variable or variables in that declaration are
- static variables and will stay in existence from call to
- call of the particular function.
-
-
-
-
- Page 36
-
-
-
-
-
-
-
-
-
- Chapter 5 - Functions, variables, and prototypes
-
-
- By putting the same reserved word in front of an
- external variable, one outside of any function, it makes the
- variable private and not accessible to use in any other
- file. This implies that it is possible to refer to external
- variables in other separately compiled files, and that is
- true. Examples of this usage will be given in chapter 14 of
- this tutorial.
-
- USING THE SAME NAME AGAIN
-
- Refer to the function named "head2". It contains
- another definition of the variable named "count". Even
- though "count" has already been defined as a global
- variable, it is perfectly all right to reuse the name in
- this function. It is a completely new variable that has
- nothing to do with the global variable of the same name, and
- causes the global variable to be unavailable in this
- function. This allows you to write programs using existing
- functions without worrying about what names were used for
- variables in the functions because there can be no conflict.
- You only need to worry about the variables that interface
- with the functions.
-
- WHAT IS A REGISTER VARIABLE?
-
- Now to fulfill a promise made earlier about what a
- register variable is. A computer can keep data in a
- register or in memory. A register is much faster in
- operation than memory but there are very few registers
- available for the programmer to use. If there are certain
- variables that are used extensively in a program, you can
- designate that those variables are to be stored in a
- register if possible in order to speed up the execution of
- the program. Turbo C allows you to use 2 register variables
- and will ignore additional requests if you request more than
- 2.
-
- Turbo C allows you to use register variables for short
- int and int types along with their unsigned counterparts. It
- also allows you to use register storage for two byte
- pointers which we will study in about 3 chapters.
-
- WHERE DO I DEFINE VARIABLES?
-
- Now for a refinement on a general rule stated earlier.
- When you have variables brought to a function as arguments
- to the function, and you are using the "classic" style of
- programming, they are defined immediately after the function
- name and prior to the opening brace for the program. Other
- variables used in the function are defined at the beginning
-
-
-
- Page 37
-
-
-
-
-
-
-
-
-
- Chapter 5 - Functions, variables, and prototypes
-
-
- of the function, immediately following the opening brace of
- the function, and before any executable statements.
-
- WHAT IS PROTOTYPING?
-
- A prototype is a "model" of the real thing and when
- programming in Turbo C, you have the ability to define a
- "model" of each function for the compiler. The compiler can
- then use the "model" to check each of your calls to the
- function and determine if you have used the correct number
- of arguments in the function call and if they are of the
- correct type. By using prototypes, you let the compiler do
- some additional error checking for you. The ANSI standard
- for C should be released late in 1987, and will contain
- prototyping as part of its recommended standard. Every good
- C compiler will have prototyping available, so you should
- learn to use it.
-
- Returning to lines 3, 4, and 5 in SCOPE.C, we have the
- prototypes for the three functions contained within the
- program. The first "void" in each line tells the compiler
- that these particular functions do not return a value, so
- that the compiler would flag the statement index = head1();
- as an error because nothing is returned to assign to the
- variable "index". The word "void" within the parentheses
- tells the compiler that this function requires no parameters
- and if a variable were included, it would be an error and
- the compiler would issue a warning message. If you wrote
- the statement head1(index);, it would be a error. This
- allows you to use type checking when programming in C in
- much the same manner that it is used in Pascal, Modula 2, or
- Ada.
-
- You should enable prototype checking with Turbo C at
- this point to see how well it works. In the "Option" menu
- select "Compiler", then "Errors", followed by "Less common
- errors", then turn on "F: Call to function with no
- prototype" by hitting the "F" key. The program SCOPE.C will
- not produce any warnings, but RECURSON.C which is next will
- result in some warning messages.
-
- Line 2 of SCOPE.C tells the system to go to the include
- files and get the file named STDIO.H which contains the
- prototypes for the standard input and output functions so
- they can be checked for proper variable types. Don't worry
- about the "include" yet, it will be covered in detail later
- in this tutorial.
-
- Compile and run this program and, when you return to
- the Integrated Environment, observe that there are no
- warning messages.
-
-
- Page 38
-
-
-
-
-
-
-
-
-
- Chapter 5 - Functions, variables, and prototypes
-
-
-
- STANDARD FUNCTION LIBRARIES
-
- Every compiler comes with some standard predefined
- functions which are available for your use. These are
- mostly input/output functions, character and string
- manipulation functions, and math functions. We will cover
- most of these in subsequent chapters. Prototypes are
- defined for you by the Turbo C compiler writer for all of
- the functions that are included with your compiler. A few
- minutes spent studying your Turbo C Reference Guide will
- give you an insight in where the prototypes are defined for
- each of the functions.
-
- In addition, most compilers have additional functions
- predefined that are not standard but allow the programmer to
- get the most out of his particular computer. In the case of
- the IBM-PC and compatibles, most of these functions allow
- the programmer to use the BIOS services available in the
- operating system, or to write directly to the video monitor
- or to any place in memory. These will not be covered in any
- detail as you will be able to study these unique aspects of
- the Turbo C compiler on your own. The entire Turbo C
- Reference Guide is devoted to defining functions. Many of
- these kinds of functions are used in the example programs in
- chapter 14.
-
- WHAT IS RECURSION?
-
- Recursion is another of those programming techniques
- that seem very intimidating the first time you come across
- it, but if you will load and display the example program
- named RECURSON.C, we will take all of the mystery out of it.
- This is probably the simplest recursive program that it is
- possible to write and it is therefore a stupid program in
- actual practice, but for purposes of illustration, it is
- excellent.
-
- Recursion is nothing more than a function that calls
- itself. It is therefore in a loop which must have a way of
- terminating. In the program on your monitor, the variable
- "index" is set to 8, and is used as the argument to the
- function "count_dn". The function simply decrements the
- variable, prints it out in a message, and if the variable is
- not zero, it calls itself, where it decrements the variable
- again, prints it, etc. etc. etc. Finally, the variable will
- reach zero, and the function will not call itself again.
- Instead, it will return to the prior time it called itself,
- and return again, until finally it will return to the main
- program and from there return to DOS.
-
-
-
- Page 39
-
-
-
-
-
-
-
-
-
- Chapter 5 - Functions, variables, and prototypes
-
-
- For purposes of understanding you can think of it as
- having 8 copies of the function "count_dn" available and it
- simply called all of them one at a time, keeping track of
- which copy it was in at any given time. That is not what
- actually happened, but it is a reasonable illustration for
- you to begin understanding what it was really doing.
-
- WHAT DID IT DO?
-
- A better explanation of what actually happened is in
- order. When you called the function from itself, it stored
- all of the variables and all of the internal flags it needs
- to complete the function in a block somewhere. The next
- time it called itself, it did the same thing, creating and
- storing another block of everything it needed to complete
- that function call. It continued making these blocks and
- storing them away until it reached the last function when it
- started retrieving the blocks of data, and using them to
- complete each function call. The blocks were stored on an
- internal part of the computer called the "stack". This is a
- part of memory carefully organized to store data just as
- described above. It is beyond the scope of this tutorial to
- describe the stack in detail, but it would be good for your
- programming experience to read some material describing the
- stack. A stack is used in nearly all modern computers for
- internal housekeeping chores.
-
- In using recursion, you may desire to write a program
- with indirect recursion as opposed to the direct recursion
- described above. Indirect recursion would be when a
- function "A" calls the function "B", which in turn calls
- "A", etc. This is entirely permissible, the system will
- take care of putting the necessary things on the stack and
- retrieving them when needed again. There is no reason why
- you could not have three functions calling each other in a
- circle, or four, or five, etc. The C compiler will take
- care of all of the details for you.
-
- The thing you must remember about recursion is that at
- some point, something must go to zero, or reach some
- predefined point to terminate the loop. If not, you will
- have an infinite loop, and the stack will fill up and
- overflow, giving you an error and stopping the program
- rather abruptly.
-
- Compile and run this program. If you left the
- prototype checking on from the last program you will find
- several "warnings" in the message window when you return
- to the Integrated Environment. Study these for a few
- minutes. One of the suggested exercises at the end of this
-
-
-
- Page 40
-
-
-
-
-
-
-
-
-
- Chapter 5 - Functions, variables, and prototypes
-
-
- chapter is to modify this program to eliminate the prototype
- warnings.
-
- ANOTHER EXAMPLE OF RECURSION
-
- The program named BACKWARD.C is another example of
- recursion, so load it and display it on your screen. This
- program is similar to the last one except that it uses a
- character array. Each successive call to the function named
- "forward_and_backwards" causes one character of the message
- to be printed. Additionally, each time the function ends,
- one of the characters is printed again, this time backwards
- as the string of recursive function calls is retraced.
-
- This program uses the "modern" method of function
- definition and includes full prototype definitions. The
- "modern" method of function definition moves the types of
- the variables into the parentheses along with the variable
- names themselves. The final result is that the line
- containing the function name looks more like the
- corresponding line in Pascal, Modula 2, or Ada.
-
- Don't worry about the character array defined in line 9
- or the other new material presented here. After you
- complete chapter 7 of this tutorial, this program will make
- sense. It was felt that introducing a second example of
- recursion was important so this file is included here.
-
- Compile and run this program with prototype checking
- on, and observe the results.
-
- HOW TO WORK AROUND THE TURBO C (v1.0) BUG
-
- Load and display the program named FLOATSQ2.C which is
- an exact copy of the program FLOATSQ.C which we considered
- earlier with prototyping added. The return of the erroneous
- zeros is now repaired and the correct values are returned.
- Apparently, when the coders of Turbo C at Borland were
- testing this compiler, they used prototyping and never found
- this bug. The use of prototyping is a good practice for all
- C programmers to get into. Note that if you are using
- version 1.5 of TURBO C this file will also compile correctly
- so you can use either method of programming. It would be to
- your advantage to learn the newer method using prototypes.
-
- Several things should be mentioned about this program.
- First, the word "float" at the beginning of lines 27 and 35
- indicate to the compiler that these functions are functions
- that return "float" type values. Also, since the prototypes
- are given before "main", the functions are not required to
- be identified in line 12 as they were in line 7 of FLOATSQ.C
-
-
- Page 41
-
-
-
-
-
-
-
-
-
- Chapter 5 - Functions, variables, and prototypes
-
-
- earlier in this chapter. They can be included in line 12,
- but they are not required to be.
-
- Notice also that the type of the variable "inval" is
- included within the parentheses in line 27. It would be
- very educational for you to modify this program so that you
- included a call to "sqr" with a variable of type "int"
- within the parentheses to see what kind of a warning you
- would get. Do the same thing in the program without
- prototype checking, FLOATSQ.C.
-
-
-
- PROGRAMMING EXERCISES
-
- 1. Rewrite TEMPCONV.C, from an earlier chapter, and move
- the temperature calculation to a function.
-
- 2. Write a program that writes your name on the monitor 10
- times by calling a function to do the writing. Move the
- called function ahead of the "main" function to see if
- the Turbo C compiler will allow it.
-
- 3. Add prototyping to the program named RECURSON.C to
- eliminate the warnings.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Page 42
-